use pest::Parser;
use pest_derive::Parser;
use std::env;
use std::fs;
use std::process;

#[derive(Parser)]
#[grammar = "sysylex.pest"]
pub struct SysYLexer;

#[derive(Debug, Clone)]
pub struct Token {
    pub token_type: String,
    pub value: String,
    pub line: usize,
    pub column: usize,
}

#[derive(Debug, Clone)]
pub struct LexError {
    pub error_type: String,
    pub line: usize,
    pub message: String,
}

fn main() {
    let args: Vec<String> = env::args().collect();
    
    if args.len() != 2 {
        eprintln!("Usage: {} <filename>", args[0]);
        process::exit(1);
    }
    
    let filename = &args[1];
    
    // 检查文件扩展名
    if !filename.ends_with(".sy") {
        eprintln!("Error: File must have .sy extension");
        process::exit(1);
    }
    
    // 读取文件内容
    let content = match fs::read_to_string(filename) {
        Ok(content) => content,
        Err(err) => {
            eprintln!("Error: Cannot read file {}: {}", filename, err);
            process::exit(1);
        }
    };
    
    // 进行词法分析
    let (tokens, errors) = analyze_tokens(&content);
    
    if !errors.is_empty() {
        // 有词法错误，输出所有错误信息
        for error in errors {
            eprintln!("Error type {} at Line {}:{}", error.error_type, error.line, error.message);
        }
    } else {
        // 输出所有token信息
        for token in tokens {
            eprintln!("{} {} at Line {}.", token.token_type, token.value, token.line);
        }
    }
}

fn analyze_tokens(input: &str) -> (Vec<Token>, Vec<LexError>) {
    let mut tokens = Vec::new();
    let mut errors = Vec::new();
    
    // 首先处理整个输入的块注释
    let input_without_block_comments = remove_block_comments(input);
    
    // 逐行处理以便准确定位错误
    for (line_num, line) in input_without_block_comments.lines().enumerate() {
        let line_num = line_num + 1;
        
        // 移除行注释
        let line_without_comments = remove_line_comments(line);
        if line_without_comments.trim().is_empty() {
            continue;
        }
        
        // 使用混合解析方法处理整行
        parse_line_mixed(&line_without_comments, &mut tokens, &mut errors, line_num);
    }
    
    (tokens, errors)
}

fn remove_block_comments(input: &str) -> String {
    let mut result = String::new();
    let mut chars = input.chars().peekable();
    
    while let Some(ch) = chars.next() {
        if ch == '/' {
            if let Some(&next_ch) = chars.peek() {
                if next_ch == '*' {
                    // 块注释开始
                    chars.next(); // 消费 '*'
                    let mut found_end = false;
                    while let Some(ch) = chars.next() {
                        if ch == '*' {
                            if let Some(&next_ch) = chars.peek() {
                                if next_ch == '/' {
                                    chars.next(); // 消费 '/'
                                    found_end = true;
                                    break;
                                }
                            }
                        }
                    }
                    if !found_end {
                        // 块注释未结束，但我们已经处理完了
                    }
                } else {
                    result.push(ch);
                }
            } else {
                result.push(ch);
            }
        } else {
            result.push(ch);
        }
    }
    
    result
}

fn remove_line_comments(line: &str) -> String {
    let mut result = String::new();
    let mut chars = line.chars().peekable();
    
    while let Some(ch) = chars.next() {
        if ch == '/' {
            if let Some(&next_ch) = chars.peek() {
                if next_ch == '/' {
                    // 行注释，忽略剩余部分
                    break;
                } else {
                    result.push(ch);
                }
            } else {
                result.push(ch);
            }
        } else {
            result.push(ch);
        }
    }
    
    result
}

fn parse_line_mixed(line: &str, tokens: &mut Vec<Token>, errors: &mut Vec<LexError>, line_num: usize) {
    let mut chars = line.chars().peekable();
    let mut column = 1;
    let mut byte_pos = 0;
    
    while let Some(ch) = chars.peek() {
        if ch.is_whitespace() {
            let ch = chars.next().unwrap();
            column += 1;
            byte_pos += ch.len_utf8();
            continue;
        }
        
        // 检查特殊情况：数字后跟字母（如2i）或十六进制数（如0x1a）
        if ch.is_ascii_digit() {
            let start_col = column;
            let mut number = String::new();
            
            // 收集数字部分
            while let Some(&ch) = chars.peek() {
                if ch.is_ascii_digit() {
                    let ch = chars.next().unwrap();
                    number.push(ch);
                    column += 1;
                    byte_pos += ch.len_utf8();
                } else {
                    break;
                }
            }
            
            // 检查十六进制数（0x或0X开头）
            if number == "0" {
                if let Some(&next_ch) = chars.peek() {
                    if next_ch == 'x' || next_ch == 'X' {
                        // 这是十六进制数，收集完整的十六进制数
                        let ch = chars.next().unwrap();
                        number.push(ch); // 添加 'x' 或 'X'
                        column += 1;
                        byte_pos += ch.len_utf8();
                        
                        // 收集十六进制数字
                        while let Some(&ch) = chars.peek() {
                            if ch.is_ascii_hexdigit() {
                                let ch = chars.next().unwrap();
                                number.push(ch);
                                column += 1;
                                byte_pos += ch.len_utf8();
                            } else {
                                break;
                            }
                        }
                        
                        // 转换为十进制并添加token
                        let decimal_value = convert_to_decimal(&number);
                        tokens.push(Token {
                            token_type: "INTEGER_CONST".to_string(),
                            value: decimal_value.to_string(),
                            line: line_num,
                            column: start_col,
                        });
                        continue;
                    }
                }
            }
            
            // 检查是否跟着字母（特殊情况：2i）
            if let Some(&next_ch) = chars.peek() {
                if next_ch.is_ascii_alphabetic() {
                    // 分解为数字和标识符
                    tokens.push(Token {
                        token_type: "INTEGER_CONST".to_string(),
                        value: number.clone(),
                        line: line_num,
                        column: start_col,
                    });
                    
                    // 收集字母部分
                    let mut ident = String::new();
                    while let Some(&ch) = chars.peek() {
                        if ch.is_ascii_alphabetic() || ch == '_' {
                            let ch = chars.next().unwrap();
                            ident.push(ch);
                            column += 1;
                            byte_pos += ch.len_utf8();
                        } else {
                            break;
                        }
                    }
                    
                    tokens.push(Token {
                        token_type: "IDENT".to_string(),
                        value: ident,
                        line: line_num,
                        column: start_col + number.len(),
                    });
                    continue;
                }
            }
            
            // 检查08这种情况（八进制中包含8或9）
            if number.starts_with('0') && number.len() > 1 {
                let rest = &number[1..];
                if rest.chars().any(|c| c >= '8' && c <= '9') {
                    // 分解为多个单独的数字
                    for (i, digit_char) in number.chars().enumerate() {
                        tokens.push(Token {
                            token_type: "INTEGER_CONST".to_string(),
                            value: digit_char.to_string(),
                            line: line_num,
                            column: start_col + i,
                        });
                    }
                    continue;
                }
            }
            
            // 正常数字，直接处理
            let decimal_value = convert_to_decimal(&number);
            tokens.push(Token {
                token_type: "INTEGER_CONST".to_string(),
                value: decimal_value.to_string(),
                line: line_num,
                column: start_col,
            });
            // 数字已经被chars.next()消费了，继续处理下一个字符
        } else {
            // 非数字开头，使用pest解析
            let remaining_line = &line[byte_pos..];
            if let Some(end_bytes) = parse_single_token_with_pest(remaining_line, tokens, errors, line_num, column) {
                // 跳过已处理的字符
                let mut bytes_consumed = 0;
                while bytes_consumed < end_bytes {
                    if let Some(ch) = chars.next() {
                        bytes_consumed += ch.len_utf8();
                        column += 1;
                    } else {
                        break;
                    }
                }
                byte_pos += end_bytes;
            } else {
                // 如果pest解析失败，跳过这个字符并报告错误
                let error_char = chars.next().unwrap();
                errors.push(LexError {
                    error_type: "A".to_string(),
                    line: line_num,
                    message: format!(" Mysterious character \"{}\".", error_char),
                });
                byte_pos += error_char.len_utf8();
                column += 1;
            }
        }
    }
}

fn parse_single_token_with_pest(line: &str, tokens: &mut Vec<Token>, _errors: &mut Vec<LexError>, line_num: usize, start_column: usize) -> Option<usize> {
    // 尝试解析每个可能的token类型
    let token_rules = [
        Rule::CONST, Rule::INT, Rule::VOID, Rule::IF, Rule::ELSE, Rule::WHILE, Rule::BREAK, Rule::CONTINUE, Rule::RETURN,
        Rule::EQ, Rule::NEQ, Rule::LE, Rule::GE, Rule::AND, Rule::OR,
        Rule::PLUS, Rule::MINUS, Rule::MUL, Rule::DIV, Rule::MOD, Rule::ASSIGN, Rule::LT, Rule::GT, Rule::NOT,
        Rule::L_PAREN, Rule::R_PAREN, Rule::L_BRACE, Rule::R_BRACE, Rule::L_BRACKT, Rule::R_BRACKT,
        Rule::COMMA, Rule::SEMICOLON,
        Rule::INTEGER_CONST, Rule::IDENT
    ];
    
    for &rule in &token_rules {
        if let Ok(mut pairs) = SysYLexer::parse(rule, line) {
            if let Some(pair) = pairs.next() {
                let token_str = pair.as_str();
                if !token_str.is_empty() && line.starts_with(token_str) {
                    // 检查是否是完整的token匹配
                    let token_bytes = token_str.len();
                    if token_bytes <= line.len() {
                        return collect_single_token(rule, token_str, tokens, line_num, start_column);
                    }
                }
            }
        }
    }
    
    None
}

fn collect_single_token(rule: Rule, token_str: &str, tokens: &mut Vec<Token>, line_num: usize, start_column: usize) -> Option<usize> {
    let token_bytes = token_str.len();
    
    match rule {
        Rule::CONST | Rule::INT | Rule::VOID | Rule::IF | Rule::ELSE | 
        Rule::WHILE | Rule::BREAK | Rule::CONTINUE | Rule::RETURN => {
            tokens.push(Token {
                token_type: token_str.to_uppercase(),
                value: token_str.to_string(),
                line: line_num,
                column: start_column,
            });
            return Some(token_bytes);
        }
        Rule::IDENT => {
            tokens.push(Token {
                token_type: "IDENT".to_string(),
                value: token_str.to_string(),
                line: line_num,
                column: start_column,
            });
            return Some(token_bytes);
        }
        Rule::INTEGER_CONST => {
            let decimal_value = convert_to_decimal(token_str);
            tokens.push(Token {
                token_type: "INTEGER_CONST".to_string(),
                value: decimal_value.to_string(),
                line: line_num,
                column: start_column,
            });
            return Some(token_bytes);
        }
        Rule::PLUS => { tokens.push(Token { token_type: "PLUS".to_string(), value: "+".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::MINUS => { tokens.push(Token { token_type: "MINUS".to_string(), value: "-".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::MUL => { tokens.push(Token { token_type: "MUL".to_string(), value: "*".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::DIV => { tokens.push(Token { token_type: "DIV".to_string(), value: "/".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::MOD => { tokens.push(Token { token_type: "MOD".to_string(), value: "%".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::ASSIGN => { tokens.push(Token { token_type: "ASSIGN".to_string(), value: "=".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::EQ => { tokens.push(Token { token_type: "EQ".to_string(), value: "==".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::NEQ => { tokens.push(Token { token_type: "NE".to_string(), value: "!=".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::LT => { tokens.push(Token { token_type: "LT".to_string(), value: "<".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::LE => { tokens.push(Token { token_type: "LE".to_string(), value: "<=".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::GT => { tokens.push(Token { token_type: "GT".to_string(), value: ">".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::GE => { tokens.push(Token { token_type: "GE".to_string(), value: ">=".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::AND => { tokens.push(Token { token_type: "AND".to_string(), value: "&&".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::OR => { tokens.push(Token { token_type: "OR".to_string(), value: "||".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::NOT => { tokens.push(Token { token_type: "NOT".to_string(), value: "!".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::SEMICOLON => { tokens.push(Token { token_type: "SEMICN".to_string(), value: ";".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::COMMA => { tokens.push(Token { token_type: "COMMA".to_string(), value: ",".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::L_PAREN => { tokens.push(Token { token_type: "L_PAREN".to_string(), value: "(".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::R_PAREN => { tokens.push(Token { token_type: "R_PAREN".to_string(), value: ")".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::L_BRACE => { tokens.push(Token { token_type: "L_BRACE".to_string(), value: "{".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::R_BRACE => { tokens.push(Token { token_type: "R_BRACE".to_string(), value: "}".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::L_BRACKT => { tokens.push(Token { token_type: "L_BRACKT".to_string(), value: "[".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        Rule::R_BRACKT => { tokens.push(Token { token_type: "R_BRACKT".to_string(), value: "]".to_string(), line: line_num, column: start_column }); return Some(token_bytes); }
        _ => None
    }
}

fn convert_to_decimal(value_str: &str) -> i32 {
    if value_str.starts_with("0x") || value_str.starts_with("0X") {
        // 十六进制
        let hex_part = &value_str[2..];
        // 移除前导0
        let hex_part = hex_part.trim_start_matches('0');
        if hex_part.is_empty() {
            0
        } else {
            i32::from_str_radix(hex_part, 16).unwrap_or(0)
        }
    } else if value_str.starts_with('0') && value_str.len() > 1 {
        // 八进制
        let oct_part = value_str.trim_start_matches('0');
        if oct_part.is_empty() {
            0
        } else {
            i32::from_str_radix(oct_part, 8).unwrap_or(0)
        }
    } else {
        // 十进制
        value_str.parse::<i32>().unwrap_or(0)
    }
}